/*********************************************
 *
 *  网络UDP通信方式。
 *  UDP端口10023，可处理任意IP的指定端口发来的请求，不需要知道对端IP
 *
 *  状态数据是每秒主动上报
 *
 *  测试数据: 返回的测试数据,是长度13字节字符串,其中第一位为符号位表正负,后12位为数字位
 *
 *********************************************/

#include "mainboardreceiver.h"
#include <QUdpSocket>

#include "inicfghelper.h"
#include "logger.h"

CMainBoardReceiver::CMainBoardReceiver(QObject *parent)
    : QObject{parent}
{
    ClearLastData();
}

//---------------------------------------------------
// CYJ, 2023.02.10
/**
 * @brief CMainBoardReceiver::ClearLastData
 */
void CMainBoardReceiver::ClearLastData()
{
    memset( &m_lastSysInfo, 0, sizeof(m_lastSysInfo) );
    memset( &m_lastIOSBV, 0, sizeof(m_lastIOSBV) );
    memset( &m_lastSigTie, 0, sizeof(m_lastSigTie) );
    memset( &m_lastToD, 0, sizeof(TMB_TOD_BDC_BAC) );
    memset( &m_lastBDC, 0, sizeof(TMB_TOD_BDC_BAC) );
    memset( &m_lastBAC, 0, sizeof(TMB_TOD_BDC_BAC) );
    memset( &m_lastNTP, 0, sizeof(m_lastNTP) );
    memset( &m_lastPTP, 0, sizeof(m_lastPTP) );
    memset( &m_last10MHz, 0, sizeof(m_last10MHz) );
}

//---------------------------------------------------
// CYJ, 2023.02.10
/**
 * @brief CMainBoardReceiver::Initialize
 * @return  0                   succ
 *          other               error code
 */
int CMainBoardReceiver::Initialize()
{
    Invalidate();
    ClearLastData();

#ifdef _DEBUG
    TestParser();
#endif //_DEBUG

    m_nDstPort = GetCfgValue_Int( "mainboard/mainboard_port", 0 );
    if( m_nDstPort <= 0 )
        m_nDstPort = 10023;               // 使用缺省的端口
    m_nLocalPort = GetCfgValue_Int( "mainboard/local_port", 0 );
    if( m_nLocalPort <= 0 )
        m_nLocalPort = 10024;               // 使用缺省的端口

    QString strDstIP = GetCfgValue_String( "mainboard/mainboard_ip", "" );
    if( strDstIP.isEmpty() )
    {
        my_dbg_printf( "mainboard IP is need, using 127.0.0.1\n" );
        strDstIP = "127.0.0.1";
    }
    m_DstAddr = QHostAddress( strDstIP );

    return CreateUdpSocket();
}

//---------------------------------------------------
// CYJ, 2023.02.10
/**
 * @brief CMainBoardReceiver::Invalidate
 */
void CMainBoardReceiver::Invalidate()
{
    if( m_pUdpSocket )
        delete m_pUdpSocket;
    m_pUdpSocket = nullptr;
}

//-------------------------------------------
// CYJ, 2023.02.10
/**
 * @brief CCoviewDataReceiver::CreateUdpSocket
 */
int CMainBoardReceiver::CreateUdpSocket()
{
    m_pUdpSocket = new QUdpSocket( this );
    if( nullptr == m_pUdpSocket )
    {
        my_dbg_printf( "CMainBoardReceiver::CreateUdpSocket, new QUdpSocket nullptr\n" );
        return ENOMEM;
    }

    QHostAddress bindAddr = QHostAddress::AnyIPv4;
    if( false == m_pUdpSocket->bind( bindAddr, m_nLocalPort, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint ) )
    {
        my_dbg_printf( "bind coview udp receiver failed.\n" );
        return EIO;
    }

    connect( m_pUdpSocket, SIGNAL(readyRead() ), this, SLOT(processPendingDatagrams()) );

    return 0;
}

//-------------------------------------------
// CYJ, 2023.02.10
/**
 * @brief CCoviewDataReceiver::processPendingDatagrams
 */
void CMainBoardReceiver::processPendingDatagrams()
{
    QByteArray datagram;

//    my_dbg_printf( "processPendingDatagrams()\n" );

    while( m_pUdpSocket->hasPendingDatagrams() )
    {
        datagram.resize( int(m_pUdpSocket->pendingDatagramSize()) );
        m_pUdpSocket->readDatagram( datagram.data(), datagram.size() );
        m_aInDataCache.append( datagram );
        ProcessInputData();
    }
}

//-------------------------------------------
// CYJ, 2023.02.10
/**
 * @brief CCoviewDataReceiver::ProcessInputData
 */
void CMainBoardReceiver::ProcessInputData()
{
    while( m_aInDataCache.size() >= 2 )
    {
        int nPos = m_aInDataCache.indexOf( '\n' );
        if( nPos < 0 )
            break;
        QByteArray strOneLine = m_aInDataCache.left( nPos );
        m_aInDataCache.remove( 0, nPos + 1 );
        strOneLine = strOneLine.trimmed();
        if( strOneLine.size() < 2 )
            continue;
        if( strOneLine[0] == '$' )
            ProcessInputData_OneLine( strOneLine );
    }
}

//-------------------------------------------
// CYJ, 2023.02.10
/**
 * @brief CCoviewDataReceiver::ProcessInputData_OneLine
 * @param strOneLine    one line
 * @note
 *  数据格式示例：$AAA,ddd,ddd,ddd,…,ddd<CR><LF>
 *      $：帧命令起始符
 *      AAA： 帧类型
 *      ddd： 帧数据,字符之间用逗号隔开
 */
void CMainBoardReceiver::ProcessInputData_OneLine( QByteArray strOneLine )
{
    emit signal_GetDataFromMainboard();

    // 删除 '$'
    strOneLine.remove( 0, 1 );
    strOneLine = strOneLine.toUpper().trimmed();

    // 获取命令
    QString strCmd;
    int nPos = strOneLine.indexOf( ',' );
    if( nPos > 0 )
    {
        strCmd = strOneLine.left( nPos );
        strOneLine.remove( 0, nPos+1 );
        strOneLine = strOneLine.trimmed();
    }
    else
    {
        strCmd = strOneLine;
        strOneLine.clear();
    }

    QStringList astrData = QString( strOneLine ).split(',');

    if( strCmd == "SYSINFO" )
    {   // 系统设备状态
        ProcessInputData_SysInfo( astrData );
        return;
    }
    if( strCmd == "IOSBV" )
    {   // 输入信号状态
        ProcessInputData_IOSBV( astrData );
        return;
    }
    if( strCmd == "SIGTIE")
    {   // 测试结果
        ProcessInputData_SIGTIE( astrData );
        return;
    }
    if(strCmd == "TTLTIE"){
        // 测试结果
        ProcessInputData_TTLTIE( astrData );
        return;
    }

    if( strCmd == "TODTIE" )
    {   // 测试结果
        ProcessInputData_TODTIE( astrData );
        return;
    }

    if( strCmd == "BDCTIE" || strCmd == "RSXTIE")
    {   // 测试结果
        ProcessInputData_BDCTIE( astrData );
        return;
    }

    if( strCmd == "BACTIE" )
    {   // 测试结果
        ProcessInputData_BACTIE( astrData );
        return;
    }

    if( strCmd == "NTPTIE" )
    {   // 测试结果
        ProcessInputData_NTPTIE( astrData );
        return;
    }

    if( strCmd == "PTPTIE" )
    {   // 测试结果
        ProcessInputData_PTPTIE( astrData );
        return;
    }

    if( strCmd == "XFREQ" )
    {   // 测试结果
        ProcessInputData_XFREQ( astrData );
        return;
    }

    // 其他命令
    emit signal_CmdResponse( strCmd, astrData );
}

//-------------------------------------------
// CYJ, 2023.02.10
/**
 * @brief ProcessInputData_SysInfo
 * @param astrData            数据行
 * @note
 *      $SYSINFO,<REF>,<LOCK>,<XTEN>,<XPPS>,<TIM><CR><LF>
 *      REF： 参考源,GPS/BDS/PPS
 *      LOCK：设备锁定状态,FREE/TRACK/LOCK
 *      XTEN：10MHz参考,N/Y,Y表示有效,N表示无效
 *      XPPS：PPS参考,N/Y,Y表示有效,N表示无效
 *      TIM：本地同步精度,单位ns
 *      FREQ：频稳模块状态,N/Y,N表示预热中,Y表示正常
 *      LiP：电池剩余电量，50表示50%
 *      LiC：电池充电状态,N/Y,Y表示充电中
 *      例如：$SYSINFO,BDS,LOCK,Y,Y,12,Y,80,N
 */
void CMainBoardReceiver::ProcessInputData_SysInfo( const QStringList & astrData )
{
    int nCount = astrData.size();
    if( nCount < 8 )
    {
        my_dbg_printf( "错误的参数个数，应该是8个，当前是%d\n", nCount );
        return;
    }

    m_lastSysInfo.m_tTimeStamp = time( nullptr );

    // 参考源
    m_lastSysInfo.m_nREF = GetExtRefSrcEnumByString( astrData[0] );
    // 设备锁定状态
    m_lastSysInfo.m_nLOCK = GetDevLockEnumByString( astrData[1] );
    // 10MHz参考, N/Y,Y表示有效,N表示无效
    m_lastSysInfo.m_bXTEN = GetBoolValue( astrData[2] );
    // PPS参考,N/Y,Y表示有效,N表示无效
    m_lastSysInfo.m_bXPPS = GetBoolValue( astrData[3] );
    // 本地同步精度,单位ns,double 类型
    m_lastSysInfo.m_fTIM = astrData[4].toDouble();
    // FREQ：频稳模块状态,N/Y,N表示预热中,Y表示正常
    m_lastSysInfo.m_bFREQ = GetBoolValue( astrData[5] );
    // LiP：电池剩余电量，50表示50%
    m_lastSysInfo.m_byLiP = astrData[6].toInt();
    // LiC：电池充电状态,N/Y,Y表示充电中
    m_lastSysInfo.m_byLiC = GetBoolValue( astrData[7] );

    my_dbg_printf( "SysInfo: Ref:%d, Lock:%d, XTen:%d, Xpps:%d, Time:%.3fns\n",\
                   m_lastSysInfo.m_nREF,\
                   m_lastSysInfo.m_nLOCK,\
                   m_lastSysInfo.m_bXTEN,\
                   m_lastSysInfo.m_bXPPS,\
                   m_lastSysInfo.m_fTIM );
    my_dbg_printf( "FREQ=%d, LiP=%d, LiC=%d\n", \
                   m_lastSysInfo.m_bFREQ,\
                   m_lastSysInfo.m_byLiP,\
                   m_lastSysInfo.m_byLiC );

    emit signal_SysInfoData( m_lastSysInfo );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief CMainBoardReceiver::GetBoolValue
 */
bool CMainBoardReceiver::GetBoolValue( QString strValue )
{
    if( strValue.isEmpty() )
        return false;
    return( strValue[0] == 'Y' );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief ProcessInputData_IOSBV
 * @param astrData            数据行
 * @note
 *      $IOSBV,<2048kHz>,<TTL>,<RS422>,<ToD>,<BAC>,<NTP>,<PTP>,<参考10M>,<待测10M>,<参考1PPS><CR><LF>
 *      2048kHz：0-无信号,1-有信号
 *      TTL：0-无信号,1-PPS,2-PPM,3-PPH,4-BDC
 *      RS422：0-无信号,1-PPS,2-PPM,3-PPH,4-BDC
 *      ToD：0-无信号,1-ZDA,*-未知
 *      BAC：0-无信号,1-有信号
 *      NTP：0-异常,1-正常
 *      PTP：0-异常,1-正常
 *      参考10M：0-无信号,1-有信号
 *      待测10M：0-无信号,1-有信号
 *      参考1PPS：0-无信号,1-有信号
 *      例如：$IOSBV,0,1,4,0,0,1,0,0,0,0
 */
void CMainBoardReceiver::ProcessInputData_IOSBV( const QStringList & astrData )
{
    int nCount = astrData.size();
    if( nCount != 10 )
    {
        my_dbg_printf( "错误的参数个数，应该是10个，当前是%d\n", nCount );
        return;
    }

    m_lastIOSBV.m_tTimeStamp = time( nullptr );

    // 2048kHz：0-无信号,1-有信号
    m_lastIOSBV.m_n2048KHz = astrData[0].toInt();

    // TTL：0-无信号,1-PPS,2-PPM,3-PPH,4-BDC
    m_lastIOSBV.m_nTTL = astrData[1].toInt();

    // RS422：0-无信号,1-PPS,2-PPM,3-PPH,4-BDC
    m_lastIOSBV.m_nRS422 = astrData[2].toInt();

    // ToD: 0-无信号,1-ZDA,*-未知
    m_lastIOSBV.m_nToD = astrData[3].toInt();

    // BAC：0-无信号,1-有信号
    m_lastIOSBV.m_nBAC = astrData[4].toInt();

    // NTP：0-异常,1-正常
    m_lastIOSBV.m_nNTP = astrData[5].toInt();

    // PTP：0-异常,1-正常
    m_lastIOSBV.m_nPTP = astrData[6].toInt();

    // 参考10M：0-无信号,1-有信号
    m_lastIOSBV.m_nRef10MHz = astrData[7].toInt();

    // 待测10M：0-无信号,1-有信号
    m_lastIOSBV.m_nMeasure10MHz = astrData[8].toInt();

    // 参考1PPS：0-无信号,1-有信号
    m_lastIOSBV.m_nRefPPS = astrData[9].toInt();

    my_dbg_printf( "[IOSBV], 2048KHz=%d, TTL=%d, RS422=%d, ToD=%d, BAC=%d, NTP=%d, PTP=%d\n",\
                    m_lastIOSBV.m_n2048KHz,\
                    m_lastIOSBV.m_nTTL,\
                    m_lastIOSBV.m_nRS422,\
                    m_lastIOSBV.m_nToD,\
                    m_lastIOSBV.m_nBAC,\
                    m_lastIOSBV.m_nNTP,\
                    m_lastIOSBV.m_nPTP );
    my_dbg_printf( "参考10MHz = %d, 待测10MHz = %d, 参考 1PPS=%d\n",\
                   m_lastIOSBV.m_nRef10MHz,\
                   m_lastIOSBV.m_nMeasure10MHz,\
                   m_lastIOSBV.m_nRefPPS );

    emit signal_IOSBV( m_lastIOSBV );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief ProcessInputData_SIGTIE
 * @param astrData            数据行
 * @note
 *      $SIGTIE,<2048kHz>,<TTL>,<RS422><CR><LF>
 *      2048kHz：2048kHz测量结果,单位ps,13字节
 *      TTL：TTL（PPS/PPM/PPH）信号测量结果,单位ps,13字节
 *      RS422：RS422（PPS/PPM/PPH）信号测量结果,单位ps,13字节
 *      时间信号，没有时间信息，只能测出来相位差。
 */
void CMainBoardReceiver::ProcessInputData_SIGTIE( const QStringList & astrData )
{
    int nCount = astrData.size();
    if( nCount != 3 )
    {
        my_dbg_printf( "错误的参数个数，应该是3个，当前是%d\n", nCount );
        return;
    }

    m_lastSigTie.m_tTimeStamp = time( nullptr );
    // 2048kHz：2048kHz测量结果,单位ps,13字节
    m_lastSigTie.m_ll2048KHz = astrData[0].toLongLong();
    // TTL：TTL（PPS/PPM/PPH）信号测量结果,单位ps,13字节
    m_lastSigTie.m_llTTL = astrData[1].toLongLong();
    // RS422：RS422（PPS/PPM/PPH）信号测量结果,单位ps,13字节
    m_lastSigTie.m_llRS422 = astrData[2].toLongLong();

    my_dbg_printf( "[SIGTIE] 2048KHz=%lld, TTL=%lld, RS422=%lld\n",\
                   m_lastSigTie.m_ll2048KHz,\
                   m_lastSigTie.m_llTTL,\
                   m_lastSigTie.m_llRS422 );

    connect(this,SIGNAL(signal_SIGTIE(TMB_SIGTIE)),this->parent(),SLOT(slot_Measure_2048KHz(TMB_SIGTIE)));
    emit signal_SIGTIE( m_lastSigTie );
}

//-------------------------------------------
// YML, 2023.02.11
/**
 * @brief ProcessInputData_SIGTIE
 * @param astrData            数据行
 * @note
 *      $SIGTIE,<2048kHz>,<TTL>,<RS422><CR><LF>
 *      2048kHz：2048kHz测量结果,单位ps,13字节
 *      TTL：TTL（PPS/PPM/PPH）信号测量结果,单位ps,13字节
 *      RS422：RS422（PPS/PPM/PPH）信号测量结果,单位ps,13字节
 *      时间信号，没有时间信息，只能测出来相位差。
 */
void CMainBoardReceiver::ProcessInputData_TTLTIE( const QStringList & astrData )
{
    int nCount = astrData.size();
    if( nCount != 3 )
    {
        my_dbg_printf( "错误的参数个数，应该是3个，当前是%d\n", nCount );
        return;
    }

    m_lastSigTie.m_tTimeStamp = time( nullptr );
    // 2048kHz：2048kHz测量结果,单位ps,13字节
    m_lastSigTie.m_ll2048KHz = astrData[0].toLongLong();
    // TTL：TTL（PPS/PPM/PPH）信号测量结果,单位ps,13字节
    m_lastSigTie.m_llTTL = astrData[1].toLongLong();
    // RS422：RS422（PPS/PPM/PPH）信号测量结果,单位ps,13字节
    m_lastSigTie.m_llRS422 = astrData[2].toLongLong();

    my_dbg_printf( "[TTLTIE] 2048KHz=%lld, TTL=%lld, RS422=%lld\n",\
                   m_lastSigTie.m_ll2048KHz,\
                   m_lastSigTie.m_llTTL,\
                   m_lastSigTie.m_llRS422 );

    connect(this,SIGNAL(signal_TTLTIE(TMB_SIGTIE)),this->parent(),SLOT(slot_Measure_TTL(TMB_SIGTIE)));
    emit signal_TTLTIE( m_lastSigTie );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief GetTod_BDC_BAC_Data
 * @param astrData              in data
 * @param outData               out data
 * @return 0                    succ
 *          other               error code
 */
int CMainBoardReceiver::GetTod_BDC_BAC_Data( const char * pszTitle, const QStringList & astrData, TMB_TOD_BDC_BAC & outData )
{
    int nCount = astrData.size();
    if( nCount != 3 )
    {
        my_dbg_printf( "错误的参数个数，应该是3个，当前是%d\n", nCount );
        return EINVAL;
    }

    outData.m_tTimeStamp = time( nullptr );
    outData.m_dwDate = GetDateValue( astrData[0] );
    outData.m_dwTime = GetTimeValue( astrData[1] );
    outData.m_llValue = astrData[2].toLongLong();

    my_dbg_printf( "[%s] date=%08d, time=%06d, value=%lld\n",\
                   pszTitle,\
                   outData.m_dwDate, outData.m_dwTime, outData.m_llValue  ); 
    return 0;
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief CMainBoardReceiver::GetDateValue
 * @param strValue          yyyy-mm-dd
 * @return 0xFFFFFFFF       失败
 *         其他              日期 yyyymmdd
 */
uint32_t CMainBoardReceiver::GetDateValue( QString strValue )
{
    QStringList astrDate = strValue.split( '-', Qt::SkipEmptyParts );
    if( astrDate.size() != 3 )
        return 0xFFFFFFFF;

    int nYear = astrDate[0].toInt();
    int nMonth = astrDate[1].toInt();
    int nDay = astrDate[2].toInt();

    return nYear * 10000 + nMonth * 100 + nDay;
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief CMainBoardReceiver::GetTimeValue
 * @param strValue          HH:MM:SS
 * @return 0xFFFFFFFF       失败
 *          其他              时间
 */
uint32_t CMainBoardReceiver::GetTimeValue( QString strValue )
{
    QStringList astrDate = strValue.split( ':', Qt::SkipEmptyParts );
    if( astrDate.size() != 3 )
        return 0xFFFFFFFF;

    int nHour = astrDate[0].toInt();
    int nMinute = astrDate[1].toInt();
    int nSecond = astrDate[2].toInt();

    return nHour * 10000 + nMinute * 100 + nSecond;
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief ProcessInputData_TODTIE
 * @param astrData            数据行
 * @note
 *      $TODTIE,<Date>,<Time>,<ToD><CR><LF>
 *      Date：日期,格式为2022-10-20,10字节
 *      Time：时间,格式为09:59:19,8字节
 *      ToD：ToD测量结果,单位ps,13字节
 */
void CMainBoardReceiver::ProcessInputData_TODTIE( const QStringList & astrData )
{
    int nRetVal = GetTod_BDC_BAC_Data( "ToD", astrData, m_lastToD );
    if( nRetVal )
        return;
    connect(this,SIGNAL(signal_ToDTIE(TMB_TOD_BDC_BAC)),this->parent(),SLOT(slot_Measure_ToD(TMB_TOD_BDC_BAC)));
    emit signal_ToDTIE( m_lastToD );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief ProcessInputData_BDCTIE
 * @param astrData            数据行
 * @note
 *      $BDCTIE,<Date>,<Time>,<BDC><CR><LF>
 *      Date：日期,格式为2022-10-20,10字节
 *      Time：时间,格式为09:59:19,8字节
 *      BDC：交流B码测量结果,单位ps,13字节
 */
void CMainBoardReceiver::ProcessInputData_BDCTIE( const QStringList & astrData )
{
    int nRetVal = GetTod_BDC_BAC_Data( "BDC", astrData, m_lastBDC );
    if( nRetVal )
        return;
    connect(this,SIGNAL(signal_BDCTIE(TMB_TOD_BDC_BAC)),this->parent(),SLOT(slot_Measure_RS422(TMB_TOD_BDC_BAC)));
    emit signal_BDCTIE( m_lastBDC );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief ProcessInputData_BACTIE
 * @param astrData            数据行
 * @note
 *      $BACTIE,<Date>,<Time>,< BAC ><CR><LF>
 *      Date：日期,格式为2022-10-20,10字节
 *      Time：时间,格式为09:59:19,8字节
 *      BAC：交流B码测量结果,单位ns,13字节
 */
void CMainBoardReceiver::ProcessInputData_BACTIE( const QStringList & astrData )
{
    int nRetVal = GetTod_BDC_BAC_Data( "BAC", astrData, m_lastBAC );
    if( nRetVal )
        return;
    connect(this,SIGNAL(signal_BACTIE(TMB_TOD_BDC_BAC)),this->parent(),SLOT(slot_Measure_BAC(TMB_TOD_BDC_BAC)));
    emit signal_BACTIE( m_lastBAC );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief CMainBoardReceiver::GetNTP_PTPData
 * @param pszTitle              title
 * @param astrData              input
 * @param outData               output
 * @return  0                   succ
 *          other               error code
 */
int CMainBoardReceiver::GetNTP_PTPData( const char * pszTitle, const QStringList & astrData, TMB_NTP_PTP & outData )
{
    int nCount = astrData.size();
    if( nCount != 4 )
    {
        my_dbg_printf( "错误的参数个数，应该是4个，当前是%d\n", nCount );
        return EINVAL;
    }

    outData.m_tTimeStamp = time( nullptr );
    outData.m_dwDate = GetDateValue( astrData[0] );
    outData.m_dwTime = GetTimeValue( astrData[1] );
    outData.m_llOffset = astrData[2].toLongLong();
    outData.m_llDelay = astrData[3].toLongLong();

    my_dbg_printf( "[%s] date=%08d, time=%06d, offset=%lld, delay=%lld\n",\
                   pszTitle,\
                   outData.m_dwDate, outData.m_dwTime, \
                   outData.m_llOffset, outData.m_llDelay );

    return 0;
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief ProcessInputData_NTPTIE
 * @param astrData            数据行
 * @note
 *      $NTPTIE,<Date>,<Time>,<Offset>,<Delay><CR><LF>
 *      Date：日期,格式为2022-10-20,10字节
 *      Time：时间,格式为09:59:19,8字节
 *      Offset：NTP测量结果Offset,单位ns,13字节
 *      Delay：NTP测量结果Delay,单位ns,13字节
 */
void CMainBoardReceiver::ProcessInputData_NTPTIE( const QStringList & astrData )
{
    int nRetVal = GetNTP_PTPData( "NTP", astrData, m_lastNTP );
    if( nRetVal )
        return;
    connect(this,SIGNAL(signal_NTPTIE(TMB_NTP_PTP)),this->parent(),SLOT(slot_Measure_NTP(TMB_NTP_PTP)));
    emit signal_NTPTIE( m_lastNTP );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief ProcessInputData_PTPTIE
 * @param astrData            数据行
 * @note
 *      $PTPTIE,<Date>,<Time>,<Offset>,<Delay><CR><LF>
 *      Date：日期,格式为2022-10-20,10字节
 *      Time：时间,格式为09:59:19,8字节
 *      Offset：PTP测量结果Offset,单位ns,13字节
 *      Delay：PTP测量结果Delay,单位ns,13字节
 */
void CMainBoardReceiver::ProcessInputData_PTPTIE( const QStringList & astrData )
{
    int nRetVal = GetNTP_PTPData( "PTP", astrData, m_lastPTP );
    if( nRetVal )
        return;
    connect(this,SIGNAL(signal_PTPTIE(TMB_NTP_PTP)),this->parent(),SLOT(slot_Measure_PTP(TMB_NTP_PTP)));
    emit signal_PTPTIE( m_lastPTP );
}

//-------------------------------------------
// CYJ, 2023.02.11
/**
 * @brief ProcessInputData_XFREQ
 * @param astrData            数据行
 * @note
 *      $XFREQ,<1ms>,<10ms>,<100ms>,<1s>,<cxp>,<freqpw>,<fz><CR><LF>
 *      频率稳定度测量:
 *      1ms：1ms测试结果（8字节）
 *      10ms：10ms测试结果（8字节）
 *      100ms：100ms测试结果（8字节）
 *      1s：1s测试结果（8字节）
 *      cxp：粗测频（8字节）
 *      freqpw：频率计算值（8字节）
 *      fz：幅度值
 */
void CMainBoardReceiver::ProcessInputData_XFREQ( const QStringList & astrData )
{
    int nCount = astrData.size();
    if( nCount != 7 )
    {
        my_dbg_printf( "错误的参数个数，应该是7个，当前是%d\n", nCount );
        return;
    }

    m_last10MHz.m_tTimeStamp = time( nullptr );

    // 1ms测试结果（8字节）
    m_last10MHz.m_f1MS = astrData[0].toDouble();
    // 10ms测试结果（8字节）
    m_last10MHz.m_f10MS = astrData[1].toDouble();
    // 100ms测试结果（8字节）
    m_last10MHz.m_f100MS = astrData[2].toDouble();
    // 1s测试结果（8字节）
    m_last10MHz.m_f1S = astrData[3].toDouble();
    // 粗测频（8字节）
    m_last10MHz.m_nCXP = astrData[4].toInt();
    // 频率计算值（8字节）
    m_last10MHz.m_fFreqPW = astrData[5].toDouble();
    // 幅度值
    m_last10MHz.m_nFZ = astrData[6].toInt();

    my_dbg_printf( "[10MHz] 1ms=%.12lf, 10ms=%.12lf, 100ms=%.12lf, 1s=%.12lf, cxp=%d, freqpw=%.12lf, fz=%d\n",\
                   m_last10MHz.m_f1MS,\
                   m_last10MHz.m_f10MS,\
                   m_last10MHz.m_f100MS,\
                   m_last10MHz.m_f1S,\
                   m_last10MHz.m_nCXP,\
                   m_last10MHz.m_fFreqPW,\
                   m_last10MHz.m_nFZ );
    connect(this,SIGNAL(signal_10MHz(TMB_10MHz)),this->parent(),SLOT(slot_Measure_10MHz(TMB_10MHz)));
    emit signal_10MHz( m_last10MHz );
}

//-------------------------------------------
// CYJ, 2023.02.13
/**
 * @brief CMainBoardReceiver::StartTesting
 * @param b2048KHz                  开始 2048KHz 测试
 * @param bTTL                      开始 TTL 测试
 * @param bRS422                    开始 RS422 测试
 * @param bToD                      开始 ToD 测试
 * @param bBAC                      开始 BAC 测试
 * @param bPTP                      开始 PTP 测试
 * @param bNTP                      开始 NTP 测试
 * @param b10MHz                    开始 10MHz 测试
 * @note
 *      目前只能进行一项测试，优先级按照传参顺序，如 b2048KHz 为 true，则忽略后续参数
 *      开始/停止测量：
 *      $START,<2048khz>,<TTL>,<RS422>,<TOD>,<BAC>,<PTP>,<NTP>,<10M><CR><LF>
 *      开始/停止标识,0=停止,1=开始
 *      示例：$START,1,0,0,0,0,0,0,0
 *      返回：$START,1,0,0,0,0,0,0,0
 */
int CMainBoardReceiver::StartTesting( bool b2048KHz, bool bTTL, bool bRS422, bool bToD, bool bBAC, bool bPTP, bool bNTP, bool b10MHz )
{
    bool abStartFlags[8];
    abStartFlags[0] = b2048KHz;
    abStartFlags[1] = bTTL;
    abStartFlags[2] = bRS422;
    abStartFlags[3] = bToD;
    abStartFlags[4] = bBAC;
    abStartFlags[5] = bPTP;
    abStartFlags[6] = bNTP;
    abStartFlags[7] = b10MHz;

    // 目前只能进行一项测试，优先级按照传参顺序，如 b2048KHz 为 true，则忽略后续参数
    for(int i=0; i<8; i++ )
    {
        if( false == abStartFlags[i] )
            continue;
        // 发现第 i 项为 true，则强制设置后续参数为 false
        for(int j=i+1; j<8; j++ )
        {
            abStartFlags[j] = false;
        }
        break;
    }

    QString strCmd = "$START";
    for(int i=0; i<8; i++ )
    {
        QString strTmp = QString( ",%1" ).arg( int( abStartFlags[i] ? 1 : 0 ) );
        strCmd.append( strTmp );
    }

    QByteArray aCmdLine = strCmd.toUtf8();
    my_dbg_printf( "[START] cmdline: %s\n", aCmdLine.constData() );

    WriteData( aCmdLine );

    return 0;
}

//-------------------------------------------
// CYJ, 2023.02.13
/**
 * @brief CMainBoardReceiver::WriteData
 * @param aData             待发送的数据
 */
void CMainBoardReceiver::WriteData( const QByteArray & aData )
{
    QMutexLocker sync( &m_SyncObj );
    if( nullptr == m_pUdpSocket )
        return;
    m_pUdpSocket->write( aData );
}

//-------------------------------------------
// CYJ, 2023.02.13
/**
 * @brief CMainBoardReceiver::TestParser
 */
void CMainBoardReceiver::TestParser()
{
#if 1
    m_aInDataCache = "$SYSINFO,NA,TRACK,N,Y,1.23,Y,51,N\r\n"
            "$IOSBV,0,1,1,1,1,1,1,1,1,1\r\n"
            "$XFREQ,6.258204e-11,4.136408e-12,1.934719e-12,5.980129e-12,10000000,1.000000e+07,13\r\n"
            "$SIGTIE,-000199998008,0000000004897,-000001994354\r\n"
            "$TTLTIE,2023-01-15,09:59:19,0000000080000\r\n"
            "$RSXTIE,2023-01-15,09:59:19,0000000080000\r\n"
            "$TODTIE,0000-00-00,00:00:00,-000137989633\r\n"
            "$BACTIE,2023-02-17,13:07:21,0000002484448\r\n"
            "$NTPTIE,2023-02-17,13:07:21,0000552694021,0000028570000\r\n"
            "$PTPTIE,2023-02-17,13:07:21,-000000000011,0000000017377\r\n";

    ProcessInputData();
#endif // 1
}
